2025-05-13
قراره مدل های مختلف سری زمانی رو به داده های دوج کوین برازش کنیم!
Ritvik Kharkar
این داداشمون اسمش ریتویک خارکار هست که ویدیو های سری زمانی ایشون رو می تونید تو یوتیوب رایگان ببینید! یکی دوره های پولسازی آشغالشو میلیونی میفروشه از اون طرف یکی دیگه به رایگان بهترین مطالب رو به اشتراک میزاره!
دستور زیر رو در لینوکس اجرا کنید تا داده ها از نوبیتکس دانلود بشه
با تغییر resolution و symbol می تونید دادههای متفاوت بگیرید ، مثلاً symbol=BTCIRT داده بیتکوین میده
زمان ها به فرمت unix time داده می شود!
دستور معادل در R
library(curl)
library(jsonlite)
tmp <- tempfile()
curl_download("https://api.nobitex.ir/market/udf/history?symbol=DOGEIRT&resolution=D&to=1862230967", tmp)
d = as.data.frame.list(fromJSON(jsonlite::prettify(readLines(tmp))))[,-1]
d$t = as.Date.POSIXct(d$t, origin="1970-01-01")
write.csv(d,"DOGEIRT-D.csv",row.names = FALSE)این کد های پایتون قدیمی هست!
import json
import pandas as pd
file = 'DOGEIRT-D'
with open(file+'.json') as train_file:
dict1 = json.load(train_file)
# converting json dataset from dictionary to dataframe
df = pd.DataFrame(data=dict1)
df = df.drop('s', axis=1)
df['t'] = pd.to_datetime(df['t'],unit='s')
df = df.set_index('t')
df.index = pd.DatetimeIndex(df.index).to_period('D')
df.to_csv(file+'.csv')اینا کد پایتونه، از اسلاید بعد همه کد ها تو R هست
| t | o | h | l | c | v |
|---|---|---|---|---|---|
| 2020-12-23 | 105.2 | 105.2 | 105.2 | 105.2 | 3490 |
| 2020-12-24 | 117.8 | 121.5 | 117.8 | 121.5 | 3469 |
| t | o | h | l | c | v | |
|---|---|---|---|---|---|---|
| 1600 | 2025-05-10 | 19220.2 | 21265.9 | 18201.0 | 19011.0 | 18125789 |
| 1601 | 2025-05-11 | 19011.0 | 21000.0 | 18807.7 | 19264.1 | 12752271 |
ارزیابی بلند مدت
ارزیابی کوتاه مدت
\(P_i\) مقدار پیش بینی شده و \(A_i\) مقدار واقعی هست.
\[MSE = \frac{1}{n}\sum_{i=1}^{n}(A_i-P_i)^2\] \[RMSE = \sqrt{MSE}\] \[MAD = \frac{1}{n}\sum_{i=1}^{n}|A_i-P_i|\]
فعلا آخرین قیمت closed price را به عنوان متغییر پاسخ در نظر میگیریم.
library(zeallot)
res_prep = function(pred,lpred,lfun){
res = matrix(nrow = length(lfun),ncol = length(lpred))
rownames(res) = names(lfun)
colnames(res) = names(lpred)
colnames(pred) = names(lpred)
for (i in 1:length(lfun)) {
res[i,] = apply(pred,2,FUN = lfun[[i]])
}
return(list(pred = pred, res = res))
}
LTE = function(lpred,data,tname="time",yname="c",percent=0.8) {
tr = head(data,round(nrow(data)*percent))
ts = tail(data,nrow(data)-nrow(tr))
extra.info = list()
pred = matrix(nrow = nrow(ts))
yind = which(colnames(ts)==yname)
for (n in names(lpred)){
lpred.out = lpred[[n]](tr,ts[,-yind,drop=FALSE])
pred = cbind(pred,lpred.out[["pred"]])
extra.info[[n]] = lpred.out[["extra.info"]]
}
pred = pred[,-1,drop=FALSE]
lfun = list(RMSE=function(x) sqrt(mean((x-ts[,yname])^2)),MAD=function(x) mean(abs(x-ts[,yname])))
c(pred,res) %<-% res_prep(pred,lpred,lfun)
# Plot
fx = as.formula(paste("~",tname))
fy = as.formula(paste("~",yname))
fig = plot_ly(mode="lines", type = "scatter")%>%
add_trace( data=tr, x = fx, y = fy,name = "train")%>%
add_trace(data=ts, x = fx, y = fy,name = "test")
for (n in colnames(pred))
fig = fig %>% add_trace(x=ts[,tname],y=pred[,n],name = n)
return (list(results = res, fig=fig, extra.info = extra.info))
}در اینجا از K-fold Cross Validation نمیتوان استفاده کرد.
باید از Rolling Cross Validation استفاده کنید که به دو روش sliding و expanding می تونه انجام بشه!
اما ممکنه بپرسید که اصلا Cross Validation چی هست؟!
STE = function(lpred,data,tname="time",yname="c",startp=0.97,sliding.time=30,is.plot=TRUE) {
tr = head(data,round(nrow(data)*startp))
ts = tail(data,nrow(data)-nrow(tr))
fx = as.formula(paste("~",tname))
fy = as.formula(paste("~",yname))
fig.base = plot_ly(mode="lines", type = "scatter")%>%
add_trace( data=tr, x = fx, y = fy,name = "train")%>%
add_trace(data=ts, x = fx, y = fy,name = "test")
pred.expand = matrix(nrow = nrow(ts),ncol = length(lpred))
pred.slide = matrix(nrow = nrow(ts), ncol = length(lpred))
yind = which(colnames(ts)==yname)
for (i in 1:nrow(ts)){
for (j in 1:length(lpred)){
pred.slide[i,j] = lpred[[j]](tail(tr,sliding.time),ts[i,-yind,drop=FALSE])[["pred"]]
pred.expand[i,j] = lpred[[j]](tr,ts[i,-yind,drop=FALSE])[["pred"]]
}
tr = rbind(tr,ts[i,])
}
lfun = list(RMSE=function(x) sqrt(mean((x-ts[,yname])^2)),MAD=function(x) mean(abs(x-ts[,yname])))
c(pred.expand,res.expand) %<-% res_prep(pred.expand,lpred,lfun)
c(pred.slide,res.slide) %<-% res_prep(pred.slide,lpred,lfun)
# Plot expanding
fig.ex = fig.base
fig.sl = fig.base
if(is.plot){
for (n in colnames(pred.expand))
fig.ex = fig.ex %>% add_trace(x=ts[,tname],y=pred.expand[,n],name = n)
# Plot sliding
for (n in colnames(pred.slide))
fig.sl = fig.sl %>% add_trace(x=ts[,tname],y=pred.slide[,n],name = n)
}
return(list(expanding=list(res=res.expand,fig=fig.ex), sliding = list(res=res.slide,fig=fig.sl)))
}این تابع یکسری پارامتر ها رو می تونه فیکس کنه.
f.fix <- function(fname,fixed) {
variable = c("tr","ts")
f.new <- function() {}
formals(f.new) <- setNames(rep(list(bquote()), length(variable)), variable)
for(i in variable) assign(i, as.symbol(i))
body(f.new) <- do.call("call", unlist(list(fname, fixed, mget(variable)),recursive = FALSE))
return(f.new)
}تشکر از GKI
m.lm_poly = function(tr,ts,n=2,x=NULL){
timeInd = which(colnames(tr)=="time")
t = as.numeric(tr[,1]-tr[1,1]+1)
ts$t = as.numeric(ts[,1]-tr[1,1]+1)
tr = tr[,-timeInd,drop=FALSE]
ts = ts[,-timeInd,drop=FALSE]
# Note that poly() returns Orthogonal Polynomials
if (!is.null(x)){
tr = tr[,c("c",x),drop=FALSE]
ts = ts[,c("t",x),drop=FALSE]
}
if (n==0)
m = lm(c~.,tr)
else
m = lm(c~poly(t,n)+.,tr)
return(list(pred = predict(m,ts), extra.info = m))
}
poly.list = list(Linear.Reg=f.fix("m.lm_poly",c(n=1)),
Poly2.Reg=f.fix("m.lm_poly",c(n=2)),
Poly3.Reg=f.fix("m.lm_poly",c(n=3)),
Poly4.Reg=f.fix("m.lm_poly",c(n=4)),
Poly9.Reg=f.fix("m.lm_poly",c(n=9)) )
LTE.poly = LTE(poly.list,df,percent = 0.8)
LTE.poly$results Linear.Reg Poly2.Reg Poly3.Reg Poly4.Reg Poly9.Reg
RMSE 13554.40 10325.791 10113.680 12267.036 926819.3
MAD 10340.61 7431.199 8893.963 9931.216 611104.1
lm.res = as.data.frame(list.rbind(lapply(LTE.poly$extra.info,glance)))
row.names(lm.res) = names(poly.list)
kable(lm.res)| r.squared | adj.r.squared | sigma | statistic | p.value | df | logLik | AIC | BIC | deviance | df.residual | nobs | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Linear.Reg | 0.0411475 | 0.0403978 | 2555.104 | 54.88613 | 0 | 1 | -11867.19 | 23740.38 | 23755.85 | 8350023627 | 1279 | 1281 |
| Poly2.Reg | 0.1816485 | 0.1803678 | 2361.416 | 141.83804 | 0 | 2 | -11765.71 | 23539.41 | 23560.04 | 7126492160 | 1278 | 1281 |
| Poly3.Reg | 0.4881062 | 0.4869036 | 1868.368 | 405.88601 | 0 | 3 | -11465.20 | 22940.40 | 22966.18 | 4457750859 | 1277 | 1281 |
| Poly4.Reg | 0.5764038 | 0.5750759 | 1700.273 | 434.07563 | 0 | 4 | -11343.93 | 22699.86 | 22730.79 | 3688824598 | 1276 | 1281 |
| Poly9.Reg | 0.7733187 | 0.7717135 | 1246.244 | 481.77667 | 0 | 9 | -10943.47 | 21908.93 | 21965.64 | 1974020629 | 1271 | 1281 |
اگر دقت کنید R² برای درجات بالاتر بهتر می شود اما مدل های با درجات بالا در cross validation ضعیف عمل می کنند
(نشانه های بیش برازش ) (over-fitting)
Call:
lm(formula = c ~ poly(t, n) + ., data = tr)
Residuals:
Min 1Q Median 3Q Max
-2868.8 -1242.5 -413.7 1041.3 10358.5
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4544.60 47.51 95.67 <2e-16 ***
poly(t, n)1 18929.53 1700.27 11.13 <2e-16 ***
poly(t, n)2 34979.01 1700.27 20.57 <2e-16 ***
poly(t, n)3 51659.86 1700.27 30.38 <2e-16 ***
poly(t, n)4 -27729.52 1700.27 -16.31 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1700 on 1276 degrees of freedom
Multiple R-squared: 0.5764, Adjusted R-squared: 0.5751
F-statistic: 434.1 on 4 and 1276 DF, p-value: < 2.2e-16
Linear.Reg Poly2.Reg Poly3.Reg Poly4.Reg Poly9.Reg
RMSE 3188.640 5269.009 10381.91 8463.841 9209.955
MAD 2569.778 4926.926 10225.60 8238.094 8969.885
Linear.Reg Poly2.Reg Poly3.Reg Poly4.Reg Poly9.Reg
RMSE 1897.167 1472.316 1343.1631 1124.1165 3910.107
MAD 1631.277 1288.861 974.5159 903.4074 3089.544
توی این مدل همه داده ها تاثیر یکسانی روی مدل دارند. هرچقدر که این مدل سعی میکنه داده های جدید رو خوب فیت کنه ، همونقدر برای برازش مناسب داده های قدیمی تلاش میکنه! برای همین توی ارزشیابی بلند مدت خیلی خوب عمل نمیکنه!
فراموشی یک نعمت است!
همانطور که می دانید بازار همیشه پستی و بلندی داره! دوره ای نزول میکنه و دوره ای صعود! پس انتظار داریم منحنی پیش بینی شده هم بدون محدودیت ، صعود و نزول کنه و قله هایی رو بسازه. اما یک چند جمله ای درجه n نهایت n-1 قله داره.
به اختصار به این مدل ها میگیم SP!
Seasonal Polynomial = SP
قبل از انتخاب تعداد فصل ، بد نیست نگاهی به نمودار ACF بندازیم
[1] 1 37 12 26 24 6 9 21 36 11
بیایید L=38 را تست کنیم!
lm.res = as.data.frame(list.rbind(lapply(LTE.sp38$extra.info,glance)))
row.names(lm.res) = names(poly.list)
kable(lm.res)| r.squared | adj.r.squared | sigma | statistic | p.value | df | logLik | AIC | BIC | deviance | df.residual | nobs | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Linear.Reg | 0.0419961 | 0.0126852 | 2591.736 | 1.432780 | 0.0440061 | 38 | -11866.62 | 23813.25 | 24019.46 | 8342634210 | 1242 | 1281 |
| Poly2.Reg | 0.1827568 | 0.1570739 | 2394.736 | 7.115893 | 0.0000000 | 39 | -11764.84 | 23611.68 | 23823.05 | 7116840572 | 1241 | 1281 |
| Poly3.Reg | 0.4888624 | 0.4723741 | 1894.637 | 29.649027 | 0.0000000 | 40 | -11464.25 | 23012.51 | 23229.03 | 4451165825 | 1240 | 1281 |
| Poly4.Reg | 0.5769023 | 0.5629015 | 1724.458 | 41.204926 | 0.0000000 | 41 | -11343.18 | 22772.35 | 22994.03 | 3684482804 | 1239 | 1281 |
| Poly9.Reg | 0.7739886 | 0.7655635 | 1262.919 | 91.867417 | 0.0000000 | 46 | -10941.57 | 21979.14 | 22226.60 | 1968186703 | 1234 | 1281 |
Linear.Reg Poly2.Reg Poly3.Reg Poly4.Reg Poly9.Reg
RMSE 3204.035 5337.115 10511.66 8569.649 9294.532
MAD 2588.064 4995.123 10359.04 8351.951 9059.248
Linear.Reg Poly2.Reg Poly3.Reg Poly4.Reg Poly9.Reg
RMSE 2716.055 2345.729 1452.102 1619.987 3064.138
MAD 2087.984 1868.425 1123.847 1231.257 2412.725
همونطور که دیدید اضافه کردن روند فصلی به مدل برای این داده ها تاثیری نداشت!
اول از همه، مدل سری فوریه به صورت زیر هست:
\[ Z_t = \alpha_0 + \sum_{i=1}^q(\alpha_iC_i(t)+\beta_iS_i(t)) + e_t \]
به طوری که
\[ S_i(t) = Sin(2\pi f_i t),\space C_i(t) = Cos(2\pi f_i t),\space f_i=i/L \]
حالا به این چند جمله ای اضافه کنید میشه PF.
fsr.x = c()
for (i in 1:4){
Sname = paste("S",i,"L38",sep = "")
Cname = paste("C",i,"L38",sep = "")
fsr.x = c(fsr.x,Sname,Cname)
df[,Sname] = sin(2*pi*(i/38)*tr.t)
df[,Cname] = cos(2*pi*(i/38)*tr.t)
}
head(df) time c L38 S1L38 C1L38 S2L38 C2L38 S3L38
1 2020-12-23 105.2 1 0.1645946 0.9863613 0.3246995 0.94581724 0.4759474
2 2020-12-24 121.5 2 0.3246995 0.9458172 0.6142127 0.78914051 0.8371665
3 2020-12-25 123.1 3 0.4759474 0.8794738 0.8371665 0.54694816 0.9965845
4 2020-12-26 122.0 4 0.6142127 0.7891405 0.9694003 0.24548549 0.9157733
5 2020-12-27 122.0 5 0.7357239 0.6772816 0.9965845 -0.08257935 0.6142127
6 2020-12-28 118.9 6 0.8371665 0.5469482 0.9157733 -0.40169542 0.1645946
C3L38 S4L38 C4L38
1 0.87947375 0.6142127 0.7891405
2 0.54694816 0.9694003 0.2454855
3 0.08257935 0.9157733 -0.4016954
4 -0.40169542 0.4759474 -0.8794738
5 -0.78914051 -0.1645946 -0.9863613
6 -0.98636130 -0.7357239 -0.6772816
pf.list = list(Cubic.H1=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:2])),
Cubic.H2=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:4])),
Cubic.H3=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:6])),
Cubic.H4=f.fix("m.lm_poly",list(n=3,x=fsr.x[1:8]))
)
LTE.pf = LTE(pf.list,df)
LTE.pf$results Cubic.H1 Cubic.H2 Cubic.H3 Cubic.H4
RMSE 10117.854 10118.264 10117.208 10119.110
MAD 8899.661 8899.475 8898.829 8900.802
lm.res = as.data.frame(list.rbind(lapply(LTE.pf$extra.info,glance)))
row.names(lm.res) = names(pf.list)
kable(lm.res)| r.squared | adj.r.squared | sigma | statistic | p.value | df | logLik | AIC | BIC | deviance | df.residual | nobs | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Cubic.H1 | 0.4884477 | 0.4864416 | 1869.209 | 243.4827 | 0 | 5 | -11464.77 | 22943.55 | 22979.63 | 4454777047 | 1275 | 1281 |
| Cubic.H2 | 0.4884786 | 0.4856658 | 1870.620 | 173.6649 | 0 | 7 | -11464.73 | 22947.47 | 22993.87 | 4454507862 | 1273 | 1281 |
| Cubic.H3 | 0.4885172 | 0.4848953 | 1872.021 | 134.8813 | 0 | 9 | -11464.69 | 22951.37 | 23008.08 | 4454171863 | 1271 | 1281 |
| Cubic.H4 | 0.4886567 | 0.4842242 | 1873.240 | 110.2453 | 0 | 11 | -11464.51 | 22955.02 | 23022.04 | 4452957248 | 1269 | 1281 |
این بخش فعلا آزمایشی است!
[,1] [,2] [,3] [,4] [,5] [,6]
ind 113.000000 114.000000 117.000000 121.000000 131.000000 134.000000
lambda2 -5.642471 8.750651 6.873389 -5.174959 -4.784795 -4.424807
[,7] [,8] [,9] [,10] [,11] [,12]
ind 136.00000 138.000000 141.00000 142.000000 146.000000 147.000000
lambda2 6.38205 -6.802157 -9.45323 9.552504 4.216098 -7.666479
[,13] [,14] [,15] [,16] [,17] [,18]
ind 148.000000 151.000000 161.000000 308.000000 1167.00000 1168.00000
lambda2 5.474576 -5.067177 4.914192 -4.655726 11.61986 -13.49667
[,19] [,20] [,21] [,22] [,23] [,24]
ind 1169.000000 1191.00000 1194.00000 1207.000000 1414.000000 1417.000000
lambda2 5.306025 5.63628 4.22454 -4.489291 4.815531 -6.169306
[,25] [,26] [,27] [,28] [,29] [,30]
ind 1420.000000 1427.000000 1428.000000 1432.000000 1434.000000 1435.00000
lambda2 8.503256 7.080549 -4.894477 4.168727 -8.186091 5.95785
[,31] [,32] [,33] [,34] [,35] [,36]
ind 1436.000000 1437.000000 1446.000000 1448.000000 1449.000000 1450.000000
lambda2 -6.972194 5.819716 6.302553 -8.707434 7.546574 -4.408409
[,37] [,38] [,39] [,40] [,41] [,42]
ind 1456.000000 1457.00000 1463.000000 1466.000000 1467.000000 1475.000000
lambda2 5.976604 -11.43507 4.526033 4.804493 -6.229303 7.651323
[,43] [,44] [,45] [,46] [,47] [,48]
ind 1476.000000 1478.000000 1482.000000 1486.00000 1488.00000 1489.00000
lambda2 -4.345707 -4.578293 -5.749059 6.79396 6.96207 -10.31077
[,49] [,50] [,51] [,52] [,53] [,54]
ind 1490.000000 1496.000000 1501.000000 1502.000000 1530.00000 1531.000000
lambda2 7.388812 -4.246356 4.561379 -6.431484 10.07183 -5.703273
[,55] [,56]
ind 1567.000000 1599.000000
lambda2 -5.508054 6.283172
[,1] [,2] [,3] [,4] [,5] [,6]
ind 114.00000 117.000000 118.000000 132.000000 135.000000 137.000000
lambda1 11.45527 5.230996 -4.488507 8.412046 5.085073 -5.517287
[,7] [,8] [,9] [,10] [,11] [,12]
ind 138.000000 142.00000 147.000000 149.000000 161.000000 180.000000
lambda1 -7.768598 10.09757 -7.343761 -4.249807 5.841246 -4.756491
[,13] [,14] [,15] [,16] [,17] [,18]
ind 309.000000 1167.000000 1168.0000 1169.000000 1191.000000 1207.000000
lambda1 4.962013 4.901638 -11.5398 7.542296 6.628782 -5.117551
[,19] [,20] [,21] [,22] [,23] [,24]
ind 1414.000000 1418.00000 1419.00000 1420.00000 1427.000000 1428.000000
lambda1 6.117259 11.30475 11.19663 13.16503 5.761813 -4.249678
[,25] [,26] [,27] [,28] [,29] [,30]
ind 1434.000000 1435.000000 1437.000000 1447.00000 1448.000000 1449.000000
lambda1 -5.507697 6.069908 7.515722 -7.38661 -6.026429 6.288086
[,31] [,32] [,33] [,34] [,35] [,36]
ind 1450.000000 1456.00000 1457.00000 1467.000000 1468.000000 1472.000000
lambda1 -4.381962 -5.92635 -14.40444 -4.613674 4.195365 6.781904
[,37] [,38] [,39] [,40] [,41] [,42]
ind 1476.000000 1483.000000 1484.000000 1486.000000 1489.000000 1490.000000
lambda1 -8.350315 5.960602 4.480506 7.146185 -8.438455 6.140267
[,43] [,44] [,45] [,46] [,47] [,48]
ind 1491.000000 1496.000000 1502.000000 1514.000000 1524.000000 1530.000000
lambda1 -4.306765 -6.291619 -8.580261 4.331695 -4.713527 6.313017
[,49] [,50] [,51] [,52] [,53] [,54]
ind 1531.000000 1537.000000 1552.000000 1556.000000 1568.000000 1597.000000
lambda1 -7.932776 -4.954674 4.222292 -4.611948 4.502512 5.155669
[,55]
ind 1599.000000
lambda1 8.333462
مدل های بهتری میخوای؟